home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / stdlib1.exe / lha / SPRINTF.ASM < prev    next >
Assembly Source File  |  1990-07-09  |  16KB  |  819 lines

  1. stdlib        segment    para public 'slcode'
  2.         assume    cs:stdlib
  3.         extrn    sl_ISize:far, sl_ULSize:far
  4.         extrn    sl_LSize:far, sl_USize:far
  5.         extrn    sl_itoa:far, sl_free:far
  6.         extrn    sl_wtoa:far, sl_ltoa:far
  7.         extrn    sl_ultoa:far, sl_htoa:far
  8.         extrn    sl_utoa:far
  9.         extrn    sl_malloc:far, sl_realloc:far
  10. ;
  11. ;
  12. ;
  13. ; Sprintf- Like the "C" routine by the same name.  Calling sequence:
  14. ;
  15. ;               call    sprintf
  16. ;               db      "format string",0
  17. ;               dd      item1, item2, ..., itemn
  18. ;
  19. ; Just like the PRINTF routine except it performs an in-memory format
  20. ; operation rather than printing the data to the current output device.
  21. ; Returns a pointer to the formatted string in ES:DI.
  22. ; See the PRINTF routine for more details about this guy.
  23. ;
  24. ;
  25. cr        equ    0dh
  26. ff        equ    0ch
  27. lf        equ    0ah
  28. tab        equ    09h
  29. bs        equ    08h
  30. ;
  31. RtnAdrs        equ    2[bp]
  32. ;
  33. ;
  34. aindex        dw    ?
  35. aptr        dd    ?
  36. ;
  37. ;
  38. ; sp_BufSize is a public variable so the user can adjust the size.
  39. ;
  40.         public    sp_BufSize
  41. sp_BufSize    dw    2048
  42. ;
  43. ;
  44.         public    sl_sprintf
  45. sl_sprintf    proc    far
  46.         push    bp
  47.         mov    bp, sp
  48.         pushf
  49.         push    ax cx
  50. ;
  51. ; Request some memory from the system.  If there isn't enough available,
  52. ; try half as much and repeat.  If there is no memory available, return
  53. ; with the carry set.
  54. ;
  55.         mov    cx, sp_BufSize
  56. TryAgain:    call    sl_malloc
  57.         jnc    DoSPRINTF
  58.         shr    cx, 1
  59.         cmp    cx, 128            ;Need at least 128 bytes.
  60.         jae    TryAgain
  61.         pop    cx ax
  62.         popf
  63.                 pop    bp
  64.         stc
  65.         ret
  66. ;
  67. ; The following code simulates a far call to sbprintf.  We can't make the
  68. ; call because we need to skip the MOV BP, SP instruction which appears
  69. ; at the beginning of the code.
  70. ;
  71. DoSPRINTF:         push    cs            ;Push fake return address
  72.         mov    ax, offset RA
  73.         push    ax
  74.         push    bp            ;Push stuff on stack
  75.         pushf
  76.         push    ax bx cx dx di si es ds
  77.         jmp    sl_sbprintf2
  78. ;
  79. ; Return back to this point from sbprintf.
  80. ;
  81. RA:        push    di
  82.         mov    cx, 1
  83.         mov    al, ch
  84. FindLength:    cmp    al, es:[di]
  85.         jz    AtEnd
  86.         inc    cx
  87.         inc    di
  88.         jmp    FindLength
  89. ;
  90. AtEnd:        pop    di
  91.         call    sl_realloc
  92.         pop    cx ax
  93.         popf
  94.                 pop    bp
  95.         clc
  96.         ret        
  97. sl_sprintf    endp
  98. ;
  99. ;
  100. ;
  101. ;
  102. ; SBPRINTF- Like sprintf except it doesn't allocate storage for the
  103. ; formatted string.  Instead, you must pass it the address of a suitable
  104. ; buffer in es:di.
  105. ;
  106. ;
  107.         public  sl_sbprintf
  108. sl_sbprintf    proc    far
  109.         push    bp
  110.         mov    bp, sp
  111.         pushf
  112.         push    ax bx cx dx di si es ds
  113. ;
  114. ; Save ptr to buffer area.
  115. ;
  116. sl_sbprintf2:    mov    word ptr cs:aptr, di
  117.         mov    word ptr cs:aptr+2, es
  118.         mov    cs:aindex, 0
  119. ;
  120. ; Get pointers to the return address (format string).
  121. ;
  122.         cld
  123.         les    di, RtnAdrs
  124.         lds    si, RtnAdrs
  125. ;
  126. ; Okay, search for the end of the format string.  After these instructions,
  127. ; di points just beyond the zero byte at the end of the format string.  This,
  128. ; of course, points at the first address beyond the format string.
  129. ;
  130.         mov    al, 0
  131.         mov    cx, 65535
  132.     repne    scasb
  133. ;
  134. PrintItems:    lodsb            ;Get char si points at.
  135.         cmp    al, 0        ;EOS?
  136.         jz    PrintfDone
  137.         cmp    al, "%"        ;Start of a format string?
  138.         jz    FmtItem
  139.         cmp    al, "\"        ;Escape character?
  140.         jnz    PrintIt
  141.         call    GetEscChar
  142. PrintIt:    call    PutIt
  143.         jmp    PrintItems
  144. ;
  145. FmtItem:    call    GetFmtItem    ;Process the format item here.
  146.         jmp    PrintItems
  147. ;
  148. PrintfDone:    mov    RtnAdrs, di    ;Put out new return address.
  149.         pop    ds
  150.         pop    es
  151.         pop    si
  152.         pop    di
  153.         pop    dx
  154.         pop    cx
  155.         pop    bx
  156.         pop    ax
  157.         pop    bp
  158.         popf
  159.         clc
  160.         ret
  161. sl_sbprintf    endp
  162. ;
  163. ; GetEscChar- Handles items immediately following the escape character "\".
  164. ;
  165. ;    Special escape characters (upper/lower case is acceptable):
  166. ;
  167. ;        n    Newline (cr/lf)
  168. ;        t    tab
  169. ;        b    backspace
  170. ;        r    return
  171. ;        l    line feed
  172. ;        f    formfeed
  173. ;        \    \
  174. ;        %    &
  175. ;        0xhh    Char with hex character code hh.  Must have exactly
  176. ;            two hexadecimal digits.
  177. ;
  178. GetEscChar    proc    near
  179.         lodsb            ;Get next character
  180.         cmp    al, 'n'
  181.         je    RtnNL
  182.         cmp    al, 'N'
  183.         je    RtnNL
  184.         cmp    al, 't'
  185.         je    RtnTab
  186.         cmp    al, 'T'
  187.         je    RtnTab
  188.         cmp    al, 'b'
  189.         je    RtnBS
  190.         cmp    al, 'B'
  191.         je    RtnBS
  192.         cmp    al, 'r'
  193.         je    RtnRtn
  194.         cmp    al, 'R'
  195.         je    RtnRtn
  196.         cmp    al, 'l'
  197.         je    RtnLF
  198.         cmp    al, 'L'
  199.         je    RtnLF
  200.         cmp    al, 'f'
  201.         je    RtnFF
  202.         cmp    al, 'F'
  203.         je    RtnFF
  204. ;
  205. ; Check for the presence of a 0xhh value here:
  206. ;
  207.         cmp    al, '0'
  208.         jne    RtnChar
  209.         cmp    byte ptr [si], 'x'
  210.         je    GetHex
  211.         cmp    byte ptr [si], 'X'
  212.         jne    RtnChar
  213. ;
  214. ; Okay, process the hex value here.  Note that exactly two hex digits must
  215. ; follow the 0x.
  216. ;
  217. GetHex:        inc    si        ;Point at first hex digit.
  218.         lodsb            ;Get first hex digit.
  219.         and    al, 05fh    ;l.c. -> u.c.
  220.         cmp    al, 'A'
  221.         jb    GotIt
  222.         sub    al, '7'
  223. GotIt:        shl    al, 1        ;Put into H.O. nibble.
  224.         shl    al, 1
  225.         shl    al, 1
  226.         shl    al, 1
  227.         mov    ah, al        ;Save for later
  228.         lodsb            ;Get next char.
  229.         and    al, 05fh
  230.         cmp    al, 'A'
  231.         jb    GotIt2
  232.         sub    al, '7'
  233. GotIt2:        and    al, 0fh
  234.         or    al, ah
  235.         ret            ;Return hex constant.
  236. ;
  237. ; RtnNL (return Newline) cheats.  It needs to return two characters.
  238. ; Since GetEscChar only returns a single character, this code goes ahead
  239. ; and calls putc to output the CR and the returns the LF.
  240. ;
  241. RtnNL:        mov    al, cr
  242.         call    PutIt
  243.         mov    al, lf
  244.         ret
  245. ;
  246. RtnTab:        mov    al, tab
  247.         ret
  248. ;
  249. RtnBS:        mov    al, bs
  250.         ret
  251. ;
  252. RtnRtn:        mov    al, cr
  253.         ret
  254. ;
  255. RtnLF:        mov    al, lf
  256.         ret
  257. ;
  258. RtnFF:        mov    al, ff
  259. RtnChar:    ret
  260. ;
  261. GetEscChar    endp
  262. ;
  263. ;
  264. ;
  265. GetFmtItem    proc    near
  266.         lodsb                ;Get char beyond "%"
  267. ;
  268.         mov    cx, 1            ;Default field width is 1.
  269.         mov    dl, 0            ;Default is right justified
  270.         mov    dh, ' '            ;Default fill char is space.
  271.         mov    ah, ' '            ;Assume straight ptr, not handle.
  272. ;
  273. ; See if the user wants the value left justified:
  274. ;
  275.         cmp    al, '-'
  276.         jne    NotLeftJust
  277.         inc    dl            ;Set to right justified
  278.         lodsb                ;Get next character.
  279. ;
  280. ; See if the user wants to change the padding character.
  281. ;
  282. NotLeftJust:    cmp    al, '\'
  283.         jne    NoPadChange
  284.         lodsb                ;Get Padding Character.
  285.         mov    dh, al            ;Save padding character.
  286.         lodsb                ;Get next character
  287. ;
  288. ; See if the user wants a different field width:
  289. ;
  290. NoPadChange:    cmp    al, '0'
  291.         jb    NoFldWidth
  292.         cmp    al, '9'
  293.         ja    NoFldWidth
  294.         call    GetDecVal
  295. ;
  296. ; See if the user wants to specify a handle rather than a straight pointer
  297. ;
  298. NoFldWidth:    cmp    al, '^'
  299.         jne     ChkFmtChars
  300.         mov    ah, al
  301.         lodsb                ;Skip "^" character
  302. ;
  303. ; Okay, process the format characters down here.
  304. ;
  305. ChkFmtChars:    and    al, 05fh        ;l.c. -> U.C.
  306.         cmp    al, 'D'
  307.         je    PrintDec
  308.         cmp    al, 'I'
  309.         je    PrintDec
  310.         cmp    al, 'C'
  311.         je    PrintChar
  312. ;
  313.         cmp    al, 'X'
  314.         jne    TryH
  315.         jmp    PrintHexWord
  316. ;
  317. TryH:        cmp    al, 'H'
  318.         jne    TryU
  319.         jmp    PrintHexByte
  320. ;
  321. TryU:        cmp    al, 'U'
  322.         jne    TryString
  323.         jmp    PrintUDec
  324. ;
  325. TryString:    cmp    al, 'S'
  326.         jne    TryLong
  327.         jmp    PrintString
  328. ;
  329. TryLong:    cmp    al, 'L'
  330.         jne    Default
  331. ;
  332. ; If we've got the "L" modifier, this is a long value to print, get the
  333. ; data type character as the next value:
  334. ;
  335.         lodsb
  336.         and    al, 05fh        ;l.c. -> U.C.
  337.         cmp    al, 'D'
  338.         je    JmpDec
  339.         cmp    al, 'I'
  340.         jne    TryLU
  341. JmpDec:        jmp    LongDec
  342. ;
  343. TryLU:        cmp    al, 'U'
  344.         jne    TryX
  345.         jmp    LongU
  346. ;
  347. TryX:        cmp    al, 'X'
  348.         jne    Default
  349.         jmp    LongX
  350. ;
  351. ;
  352. ;
  353. ; If none of the above, simply return without printing anything.
  354. ;
  355. Default:        ret
  356. ;
  357. ;
  358. ;
  359. ;
  360. ;
  361. ; Print a signed decimal value here.
  362. ;
  363. PrintDec:    call    GetPtr            ;Get next pointer into ES:BX
  364.         mov    ax, es:[bx]        ;Get value to print.
  365.         call    sl_ISize        ;Get the size of this guy.
  366.         sub    cx, ax                 ;Compute padding
  367.         mov    ax, es:[bx]        ;Retrieve value to print.
  368.         js    NoPadDec        ;Is CX negative?
  369.         cmp    dl, 0            ;Right justified?
  370.         jne    LeftJustDec
  371.         call    PrintPad        ;Print padding characters
  372.         call    PutIti            ;Print the integer
  373.         ret                ;We're done!
  374. ;
  375. ; Print left justified value here.
  376. ;
  377. LeftJustDec:    call    PutIti
  378.         call    PrintPad
  379.         ret
  380. ;
  381. ; Print non-justified value here:
  382. ;
  383. NoPadDec:    call    PutIti
  384.         ret
  385. ;
  386. ;
  387. ;
  388. ; Print a character variable here.
  389. ;
  390. PrintChar:    call    GetPtr            ;Get next pointer into ES:BX
  391.         mov    al, es:[bx]        ;Retrieve value to print.
  392.                 dec    cx
  393.         js    NoPadChar        ;Is CX negative?
  394.         cmp    dl, 0            ;Right justified?
  395.         jne    LeftJustChar
  396.         call    PrintPad        ;Print padding characters
  397.         call    PutIt            ;Print the character
  398.         ret                ;We're done!
  399. ;
  400. ; Print left justified value here.
  401. ;
  402. LeftJustChar: